package com.ruoyi.questionBank.service.impl;


import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.ruoyi.common.exception.ItemNotFoundException;
import com.ruoyi.common.utils.ObjectUtil;
import com.ruoyi.common.vo.PageResult;
import com.ruoyi.questionBank.domain.AnswerResult;
import com.ruoyi.questionBank.domain.BuildPaperRule;
import com.ruoyi.questionBank.domain.ExamPaper;
import com.ruoyi.questionBank.domain.Question;
import com.ruoyi.questionBank.enums.QuestionTypeEnum;
import com.ruoyi.questionBank.mapper.ExamPaperMapper;
import com.ruoyi.questionBank.service.IExamPaperService;
import com.ruoyi.questionBank.service.IQuestionService;
import com.ruoyi.questionBank.vo.ExamPaperListVO;
import com.ruoyi.questionBank.vo.InsertQuestionVO;
import com.ruoyi.questionBank.vo.QuestionListVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class ExamPaperServiceImpl implements IExamPaperService {
    @Autowired
    private ExamPaperMapper paperMapper;
    @Autowired
    private IQuestionService questionService;

    @Override
    public PageResult<ExamPaper> list(ExamPaperListVO vo) {
        int total = paperMapper.size(vo);
        PageResult<ExamPaper> result = new PageResult<>(vo.getPageNo() ,vo.getPageSize() ,total);
        if(total > 0){
            List<ExamPaper> list = paperMapper.list(vo);
            result.addAll(list);
        }
        return result;
    }

    @Override
    public void insertQuestion(InsertQuestionVO vo) {
        ObjectUtil.checkNull(vo.getId() ,"paper id");
        if(vo.getQid() == null && (vo.getQidList() == null || vo.getQidList().isEmpty())){
            throw new ItemNotFoundException("question id");
        }

        ExamPaper paper = get(vo.getId());
        if(paper == null){
            throw new IllegalArgumentException("paper["+ vo.getId() +"] not exist");
        }
        if(vo.getQidList() != null){
            List<Question> qs = questionService.getEnable(vo.getQidList());
            paper.insertQuestion(qs);
        }else {
            Question question = questionService.get(vo.getQid());
            if (paper == null) {
                throw new IllegalArgumentException("question[" + vo.getQid() + "] not exist");
            }
            paper.insertQuestion(question ,vo.getSort());
        }
        paperMapper.update(paper);
    }

    @Override
    public void removeQuestion(int id ,int qid) {
        ExamPaper paper = get(id);
        if(paper == null){
            throw new IllegalArgumentException("paper["+ id +"] not exist");
        }
        paper.removeQuestion(qid);
        paperMapper.update(paper);
    }

    @Override
    public void removeQuestion(int id ,List<Integer> questionIdList) {
        ExamPaper paper = get(id);
        if(paper == null){
            throw new IllegalArgumentException("paper["+ id +"] not exist");
        }
        paper.removeQuestion(questionIdList);
        paperMapper.update(paper);
    }

    @Override
    public ExamPaper build(BuildPaperRule rule) {
        List<Question> qs = new ArrayList<>();
        qs.addAll(getQuestions(rule.getRadioSize() ,QuestionTypeEnum.RADIO));
        qs.addAll(getQuestions(rule.getCheckboxSize() ,QuestionTypeEnum.CHECKBOX));
        qs.addAll(getQuestions(rule.getJudgeSize() ,QuestionTypeEnum.JUDGE));
        qs.addAll(getQuestions(rule.getFillInSize() ,QuestionTypeEnum.FILL_IN));

        ExamPaper paper = new ExamPaper();
        paper.setName(rule.getName());
        paper.setRemark(rule.getRemark());

        List<Integer> ids = qs.stream().map(q -> q.getId()).collect(Collectors.toList());
        paper.setQuestionIdList(ids);
        paper.setQuestionDataList(qs);

        paper.setDefault();

        paperMapper.addExamPaper(paper);

        return paper;
    }

    private List<Question> getQuestions(int size ,QuestionTypeEnum typeEnum){
        QuestionListVO listVO = buildQuestionListVO(size ,typeEnum);
        if(listVO != null){
            List<Question> tmp = new ArrayList<>();
            do {
                PageResult<Question> page = questionService.get(listVO);
                tmp.addAll(page.getData());
                if(page.getTotalPage() > listVO.getPageNo() + 1 && RandomUtil.randomBoolean()){
                    listVO.setPageNo(listVO.getPageNo() + 1);
                }else {
                    break;
                }
            }while (true);
            List<Question> res = new ArrayList<>();
            if(tmp.size() > size){
                for(int i  = 0; i < size; i++) {
                    int index = RandomUtil.randomInt(tmp.size());
                    res.add(tmp.get(index));
                    tmp.remove(index);
                }
            }else {
                res = tmp;
            }
            return res;
        }
        return ListUtil.empty();
    }

    private QuestionListVO buildQuestionListVO(int size ,QuestionTypeEnum typeEnum){
        if(size > 0){
            QuestionListVO listVO = new QuestionListVO();
            listVO.setPageSize(size);
            listVO.setType(typeEnum.getType());
            listVO.setEnable(true);
            return listVO;
        }
        return null;
    }

    @Override
    public ExamPaper get(int pid) {
        return paperMapper.getById(pid);
    }

    @Override
    public AnswerResult submitAnswer(int pid, List<String> answers) {
        ExamPaper paper = get(pid);
        int correct = paper.correct(answers);
        AnswerResult result = new AnswerResult();
        result.setRight(correct);
        result.setQuestionSize(paper.questionSize());
        result.setScore(paper.answerAccuracy(correct));
        return result;
    }

    @Override
    @Transactional
    public void add(ExamPaper examPaper) {
        ObjectUtil.checkNull(examPaper.getName() ,"name");
        if (examPaper.getTheoryStatus() == 2) { //只能有一个进行中的试卷
            ExamPaper processPaper = paperMapper.getTheoryProcess();
            if (processPaper != null && processPaper.getId() != null && processPaper.getId() > 0) {
                throw new ItemNotFoundException("存在考核进行中的试卷["+processPaper.getName()+"]");
            }
        }
        if(StrUtil.isBlank(examPaper.getQuestionIds())){
            examPaper.setQuestionIds("[]");
            examPaper.setQuestionData("[]");
        }else {
            List<Integer> qids = examPaper.getQuestionIdList();
            List<Question> qs = questionService.getEnable(qids);
            examPaper.setQuestionDataList(qs);
        }
        examPaper.setDefault();
        paperMapper.addExamPaper(examPaper);
    }

    @Override
    @Transactional
    public void addDefault(ExamPaper examPaper) {
        ObjectUtil.checkNull(examPaper.getName() ,"name");
        if(StrUtil.isBlank(examPaper.getQuestionIds())){
            examPaper.setQuestionIds("[]");
            examPaper.setQuestionData("[]");
        }else {
            List<Integer> qids = examPaper.getQuestionIdList();
            List<Question> qs = questionService.getEnable(qids);
            examPaper.setQuestionDataList(qs);
        }
        examPaper.setDefault();
        paperMapper.addExamPaper(examPaper);
    }


    @Override
    @Transactional
    public void update(ExamPaper examPaper) {
        if (examPaper.getTheoryStatus() == 2) { //只能有一个进行中的试卷
            ExamPaper processPaper = paperMapper.getTheoryProcess();
            if (processPaper != null && processPaper.getId() != null && processPaper.getId() > 0) {
                throw new ItemNotFoundException("存在考核进行中的试卷["+processPaper.getName()+"]");
            }
        }
        examPaper.setQuestionData(null);
        examPaper.setQuestionIds(null);
        paperMapper.update(examPaper);
    }

    @Override
    public ExamPaper getTheoryProcess() {
        return paperMapper.getTheoryProcess();
    }

    @Override
    public void del(int id) {
        paperMapper.del(id);
    }
}
